package de.uv.kilter.core.implementation;

import java.util.List;
import java.util.Vector;

import de.uv.kilter.core.IConnection;
import de.uv.kilter.core.INode;


public class Node implements INode{
	
	private List<IConnection> inboundingConnections = null;
	private List<IConnection> outboundingConnections = null;

	private String name = null;
	private long id = 0;
	
	private int capacity = 0;
	private int originalCapacity = 0;
	
	public Node(){
		
	}
	
	public Node(String name, int capacity) {
		this.name = name;
		this.capacity = capacity;
	}
	
	public Node(String name, int capacity, List<IConnection> inboundingConnections,
			List<IConnection> outboundingConnections) {
		this(name, capacity);
		this.inboundingConnections = inboundingConnections;
		this.outboundingConnections = outboundingConnections;
	}
	
	@Override
	public void addInboundingConnection(IConnection inboundingConnection) {
		if (inboundingConnection != null) {
			if (this.inboundingConnections == null)
				this.inboundingConnections = new Vector<IConnection>();
			if (!this.inboundingConnections.contains(inboundingConnection))
				this.inboundingConnections.add(inboundingConnection);
		}
	}

	@Override
	public void addOutboundingConnection(IConnection outboundingConnection) {
		if (outboundingConnection != null) {
			if (this.outboundingConnections == null)
				this.outboundingConnections = new Vector<IConnection>();
			if (!this.outboundingConnections.contains(outboundingConnection))
				this.outboundingConnections.add(outboundingConnection);
		}
	}

	@Override
	public void clearInboundingConnections() {
		this.inboundingConnections = null;
		
	}

	@Override
	public void clearOutboundingConnections() {
		this.outboundingConnections = null;
		
	}

	@Override
	public int getCapacity() {
		return this.capacity;
	}

	@Override
	public List<IConnection> getInboundingConnections() {
		return this.inboundingConnections;
	}

	@Override
	public String getName() {
		return this.name;
	}

	@Override
	public List<IConnection> getOutboundingConnections() {
		return this.outboundingConnections;
	}

	@Override
	public void setCapacity(int capacity) {
		this.capacity = capacity;
	}
	
	@Override
	public void addCapacity(int capacity) {
		this.capacity += capacity;
	}

	@Override
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public long getId() {
		return this.id;
	}

	@Override
	public void setId(long id) {
		this.id = id;
	}

	@Override
	public void removeInboundingConnection(IConnection inboundingConnection) {
		if (this.inboundingConnections != null)
			this.inboundingConnections.remove(inboundingConnection);
		
	}

	@Override
	public void removeOutboundingConnection(IConnection outboundingConnection) {
		if (this.outboundingConnections != null)
			this.outboundingConnections.remove(outboundingConnection);
		
	}

	@Override
	public List<IConnection> getInboundingPhantomConnections() {
		List<IConnection> inboundingPhantomConnections = null;
		if (getInboundingConnections() != null) {
			for (IConnection connection: getInboundingConnections()) {
				if (connection instanceof PhantomConnection) {
					if (inboundingPhantomConnections == null)
						inboundingPhantomConnections = new Vector<IConnection>();
					inboundingPhantomConnections.add(connection);
				}
			}
		}
		return inboundingPhantomConnections;
	}

	@Override
	public void removeAllInboundingPhantomConnections() {
		List<IConnection> inboundingPhantomConnections = getInboundingPhantomConnections();
		if (inboundingPhantomConnections != null) {
			for (IConnection connection: inboundingPhantomConnections) {
				removeInboundingPhantomConnection(connection);
			}
		}
		
	}

	@Override
	public void removeInboundingPhantomConnection(IConnection inboundingPhantomConnection) {
		if (inboundingPhantomConnection instanceof PhantomConnection)
			removeInboundingConnection(inboundingPhantomConnection);
		
	}

	@Override
	public IConnection getInboundingPhantomConnectionForGivenSourceNode(
			INode sourceNode) {
		List<IConnection> inboundingPhantomConnection = getInboundingPhantomConnections();
		if (inboundingPhantomConnection != null) {
			for (IConnection connection: inboundingPhantomConnection) {
				if (connection.getSourceNode().equals(sourceNode))
					return connection;
			}
		}
		return null;
	}

	@Override
	public IConnection getOutboundingPhantomConnectionForGivenTargetNode(
			INode targetNode) {
		List<IConnection> outboundingPhantomConnection = getOutboundingPhantomConnections();
		if (outboundingPhantomConnection != null) {
			for (IConnection connection: outboundingPhantomConnection) {
				if (connection.getSourceNode().equals(targetNode))
					return connection;
			}
		}
		return null;
	}

	@Override
	public List<IConnection> getOutboundingPhantomConnections() {
		List<IConnection> outboundingPhantomConnections = null;
		if (getOutboundingConnections() != null) {
			for (IConnection connection: getOutboundingConnections()) {
				if (connection instanceof PhantomConnection) {
					if (outboundingPhantomConnections == null)
						outboundingPhantomConnections = new Vector<IConnection>();
					outboundingPhantomConnections.add(connection);
				}
			}
		}
		return outboundingPhantomConnections;
	}

	@Override
	public void removeAllOutboundingPhantomConnections() {
		List<IConnection> phantomConnectionsToBeRemoved = getOutboundingPhantomConnections();
		if (phantomConnectionsToBeRemoved != null) {
			for (IConnection connection: phantomConnectionsToBeRemoved) {
				removeOutboundingPhantomConnection(connection);
			}
		}
	}

	@Override
	public void removeOutboundingPhantomConnection(
			IConnection outboundingPhantomConnection) {
		if (outboundingPhantomConnection instanceof PhantomConnection)
			removeOutboundingConnection(outboundingPhantomConnection);		
	}

	@Override
	public int getOriginalCapacity() {
		return originalCapacity;
	}

	@Override
	public void setOriginalCapacity(int originalCapacity) {
		this.originalCapacity = originalCapacity;
	}

	@Override
	public void addOriginalCapacity(int originalCapacity) {
		this.originalCapacity += originalCapacity;
	}
	
	/**
	 * @see de.uv.kilter.core.INode#getMarkableNodes()
	 */
	@Override
	public List<INode> getMarkableNodes() {
		List<INode> result = new Vector<INode>();
		
		if (inboundingConnections != null)
			for (IConnection connection: inboundingConnections)
			{
				if((connection.getDecreasedCost() < 0 &&
					connection.getLoad() > connection.getMaximumCapacity()) ||
				   (connection.getDecreasedCost() >= 0 &&
					connection.getLoad() > connection.getMinimumCapacity()))
					result.add(connection.getSourceNode());
			}
		
		if (outboundingConnections != null)
			for (IConnection connection: outboundingConnections)
			{
				if((connection.getDecreasedCost() > 0 &&
					connection.getLoad() < connection.getMinimumCapacity()) ||
				   (connection.getDecreasedCost() <= 0 &&
					connection.getLoad() < connection.getMaximumCapacity()))
					result.add(connection.getTargetNode());
			}
	
		if (result.size() == 0)
			return null;
		else
			return result;
	}
	
	@Override
	public String toString() {
		return getName() + " Kapazität:" + getCapacity() + " o.Kapazität:" + getOriginalCapacity();
	}
	
	/**
	 * @see de.uv.kilter.core.INode#getCopyWithoutConnections()
	 */
	@Override
	public INode getCopyWithoutConnections() {
		INode node = new Node();
		node.setCapacity(this.getCapacity());
		node.setId(this.getId());
		node.setName(this.getName());
		node.setOriginalCapacity(this.getOriginalCapacity());
		return node;
	}
}
